package com.eagle.springservlet.controller;

import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.Random;
import java.util.concurrent.*;

/***
 * {@link org.springframework.web.bind.annotation.RestController}
 *
 * @author: eagle
 * @since: 2019/1/31
*/
@RestController
@EnableScheduling
public class HelloWorldAsyncController {
	private final BlockingQueue<DeferredResult<String>> queue = new ArrayBlockingQueue<>(5);

	// 超时随机数
	private final Random random = new Random();

	@Scheduled(fixedRate = 5000) //5s执行一次， 配合index()方法使用
	public void process() throws InterruptedException { // 定时操作
		DeferredResult<String> result = null;
		do {
			result = queue.take();
			// 随机超时时间
			long timeout = random.nextInt(100);
			// 模拟等待时间，RPC 或者 DB 查询
			Thread.sleep(timeout);
			// 计算结果,会触发index()的onCompletion方法
			result.setResult("Hello,World");
			println("执行计算结果，消耗：" + timeout + " ms.");
		} while (result != null);
	}

	@RequestMapping("hello-world")
	public DeferredResult<String> index() {
		//非timeout得时候，onCompletion和主线程会是同一个线程
		//在最终返回时候，还是会堵塞
		DeferredResult<String> result = new DeferredResult<>(500L); //500毫秒
		// 入队操作
        queue.offer(result);
		println("主线程开始");

		result.onCompletion(() -> {
			println("副线程process()-->执行最终结束");
		});

		result.onTimeout(() -> {
			println("副线程process()-->执行超时");
		});

		println("主线程结束");
		return result;
	}

	//代替process()+index()的方案
	@GetMapping("/callable-hello-world")
	public Callable<String> callableHelloWorld() {
		final long startTime = System.currentTimeMillis();

		println("Hello,World");

		return () -> {
			long costTime = System.currentTimeMillis() - startTime;
			println("执行计算结果，消耗：" + costTime + " ms.");
			return "Hello,World";
		};
	}

	@GetMapping("/completion-stage")
	public CompletionStage<String> completionStage(){
		final long startTime = System.currentTimeMillis();

		println("Hello,World");

		return CompletableFuture.supplyAsync(()->{
			long costTime = System.currentTimeMillis() - startTime;
			println("执行计算结果，消耗：" + costTime + " ms.");
			return "Hello,World"; // 异步执行结果
		});
	}


	private static void println(Object object) {
		String threadName = Thread.currentThread().getName();
		System.out.println("HelloWorldAsyncController[" + threadName + "]: " + object);
	}


}

